package com.example.smartgreenhouse.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {

    /**
     * 使用成员变量 EXPIRE_TIME 来设置令牌的过期时间
     * 使用成员变量 SECRET 来存放加密和解密令牌的密钥
     *使用 @Value 注解来注入配置文件中的属性，更加灵活，解耦
     */
    @Value("${jwt.secret}")
    private String SECRET;

    @Value("${jwt.token.BaiLian}")
    private String BaiLianToken;


    //过期时间,单位是毫秒
    private static long EXPIRE_TIME = 24*60*60*1000;


    /**
     * sign函数用于生成JWT token，并将用户的ID，用户的角色以及
     * 过期具体时间（按照yyyy-MM-dd HH:mm:ss）存放在token中
     * 采用HMAC256算法利用密钥对JWT token进行加密
     * 最后返回一个JWT token或者一个错误信息
     */
    public String sign(String userId, String role) {
        try {
            Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            // 将过期时间转换为格式化字符串
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String formattedExpirationDate = sdf.format(expirationDate);
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            return JWT.create()
                    .withClaim("userId", userId)
                    .withClaim("role", role)
                    .withClaim("expirationDate", formattedExpirationDate) // 存储传入的格式化过期时间
                    .withExpiresAt(expirationDate) // 使用 Date 类型的过期时间
                    .sign(algorithm);
        } catch (Exception e) {
            // 记录异常
            System.err.println("生成 JWT 失败: " + e.getMessage());
            // 返回一个自定义的错误消息
            return "Error generating token";
        }
    }
    /**
     * checkSign用于验证接收的token是否有效
     *并返回token是否有效
     */
    public Map<String,String> checkSign(String token) throws TokenExpiredException {
        try {
            if(token.equals(BaiLianToken)){
                Map<String,String> map = new HashMap<>();
                map.put("userId","10");
                map.put("role","BaiLianAI");
                map.put("expirationDate","2999-12-31 23:29:59");
                return map;
            }
            else {
                Algorithm algorithm = Algorithm.HMAC256(SECRET);
                JWTVerifier verifier = JWT.require(algorithm)
                        .build();
                verifier.verify(token);
                return parseToken(token);
            }
        }catch (JWTVerificationException exception) {
            return null; // token 验证失败
        }
    }

    /**
     * parseToken用于接收一个token并对其进行解析
     * 函数返回从JWT中解析得到的用户信息(用户的ID,用户的角色以及Token的过期时间)
     * 或者返回相应的错误信息。
     */
    public Map<String,String> parseToken(String token) {
        try {
            if(token.equals(BaiLianToken)){
                Map<String,String> map = new HashMap<>();
                map.put("userId","10");
                map.put("role","BaiLianAI");
                map.put("expirationDate","2999-12-31 23:29:59");
                return map;
            }
            else {
                DecodedJWT decodedJWT = JWT.decode(token);
                String userId = decodedJWT.getClaim("userId").asString();
                String role = decodedJWT.getClaim("role").asString();
                String formattedExpirationDate = decodedJWT.getClaim("expirationDate").asString();
                Map<String,String> map = new HashMap<>();
                map.put("userId",userId);
                map.put("role",role);
                map.put("expirationDate",formattedExpirationDate);
                return map;
            }
        } catch (JWTDecodeException e) {
            // 记录异常
            System.err.println("解析 token 失败: " + e.getMessage());
            // 返回包含错误信息的 Map
            Map<String, String> errorMap = new HashMap<>();
            errorMap.put("error", "Invalid token");
            return errorMap;
        }
    }
}
